#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_spi.h"
#include "stm32f4xx_exti.h"
#include "misc.h"
#include "drv_systick.h"
#include "drv_sx1278.h"
#include "stm32f4xx.h"
#include "stm32f4xx_syscfg.h"
#include <stdio.h>


//static unsigned char   Frequency[3]={0x75,0x94,0x00};	// 470.311
static unsigned char   Frequency[3]={0x6c,0x80,0x00};
static unsigned char   SpreadingFactor=11;             //扩频因子,7-12,扩频因子选小一些，发射时间会更快一些。
static unsigned char   CodingRate=1;                   //编码率,1-4
static unsigned char   Bw_Frequency=8;                 //信号带宽,6-9
static unsigned char   powerValue= 15;                 //功率设置,作为power_data数组的索引
static unsigned char   power_data[16]={0X80,0X81,0X82,0X83,0X84,0X85,0X86,0X87,0X88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f};
unsigned char sg_sx1278TxBusy=0;
uint8_t sg_sx1278RecvBuf[64]={0};
uint8_t sg_sx1278RecvLen=0;
uint8_t sg_sx1278RecvFlag=0;

/**
 * 功能：设置NSS引脚状态
 * 参数：
 *       status:非0值表示拉高NSS,0表示拉低NSS
 * 返回值：None
 */
static void sx1278SetNss(uint8_t status)
{
    if(status != 0) //拉高NSS
    {
        GPIO_SetBits(GPIOC, GPIO_Pin_12);  
    }else          //拉低NSS
    {
        GPIO_ResetBits(GPIOC, GPIO_Pin_12);  
    }
}

/**
 * 功能：发送一字节
 * 参数：
 *       SPIx:指定SPI
 *       byte:待发送数据
 * 返回值：None
 */
static void sx1278SendByte(uint16_t byte)
{
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);     //等待发送缓冲区为空
    SPI_I2S_ClearFlag(SPI1,SPI_I2S_FLAG_TXE);

    SPI_I2S_SendData(SPI1, byte);

    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);     //等待接收缓冲区非空
    SPI_I2S_ClearFlag(SPI1,SPI_I2S_FLAG_RXNE);
	
	SPI_I2S_ReceiveData(SPI1);
}

/**
 * 功能：接收一字节
 * 参数：
 *       SPIx:指定SPI
 * 返回值：读取到的数据
 */
static uint16_t sx1278RcvByte(void)
{
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);     //等待发送缓冲区为空
    SPI_I2S_ClearFlag(SPI1,SPI_I2S_FLAG_TXE);

    SPI_I2S_SendData(SPI1, 0xff);

    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);     //等待接收缓冲区非空
    SPI_I2S_ClearFlag(SPI1,SPI_I2S_FLAG_RXNE);
	
	return SPI_I2S_ReceiveData(SPI1);
}

/**
 * 功能：复位SX1278,只在初始化之前复位
 * 参数：None
 * 返回值：None
 */
static void sz1278Reset(void)
{
    GPIO_ResetBits(GPIOC, GPIO_Pin_10);
    SYSTICK_DelayNms(125);
    GPIO_SetBits(GPIOC, GPIO_Pin_10);
    SYSTICK_DelayNms(300);
}

/**
 * 功能：向SX1278指定地址中写入数据，通常用作更改某寄存器中的值
 * 参数：
 *       addr:寄存器地址，寄存器地址参考头文件或者官方手册
 *            读或写由地址最高位决定
 *       byte:待发送数据
 * 返回值：None
 */
static void sx1278WriteByte(unsigned char addr, unsigned char data)
{ 
	sx1278SetNss(0);                      //拉低NSS
	sx1278SendByte(addr|0x80);
	sx1278SendByte(data);
	sx1278SetNss(1);                      //拉高NSS
}

/**
 * 功能：读取SX1278返回的数据
 * 参数：
 *       addr:寄存器地址，寄存器地址参考头文件或者官方手册
 *            读或写由地址最高位决定
 * 返回值：返回指定寄存器当中的值
 */	
static unsigned char sx1278ReadByte(unsigned char addr)
{
	unsigned char Value;

	sx1278SetNss(0);                      //拉低NSS
	sx1278SendByte(addr&0x7f);
	Value = sx1278RcvByte();
	sx1278SetNss(1);                     //拉高NSS
	
	return Value; 
}

/**
 * 功能：设置SX1278工作状态
 * 参数：
 *       opMode:操作模式 取值见RFMode_SET枚举
 * 返回值：None
 */	
static void sx1278SetOpMode(en_rf_mode_set_t opMode )
{
	unsigned char opModePrev;
	opModePrev=sx1278ReadByte(REG_LR_OPMODE);     //读0x01模式寄存器
	opModePrev &=0xf8;                        //清零低三位
	opModePrev |= (unsigned char)opMode;      //或上形参
	sx1278WriteByte(REG_LR_OPMODE, opModePrev);   //重新写回去	
}

/**
 * 功能：设置SX1278工作模式
 * 参数：
 *       opMode:分为FSK和LoRa两种，通常选择LoRa
 * 返回值：None
 */	
static void sx1278SetLoRaFSK(en_debug_fsk_ook_t opMode )
{
	unsigned char opModePrev;
	opModePrev=sx1278ReadByte(REG_LR_OPMODE); //读0x01模式寄存器
	opModePrev &=0x7F; //清零最高位
	opModePrev |= (unsigned char)opMode;  //或上形参
	sx1278WriteByte( REG_LR_OPMODE, opModePrev); //重新写回去		
}

/**
 * 功能：设置SX1278射频频率
 * 参数：None
 * 返回值：None
 * 补充：射频频率= (Frequency[0]<<16 | Frequency[1]<<8 |  Frequency[2])*61.035
 *       即射频频率 = 0x6C8000 * 61.035 = 433.99MHz
 */	
static void sx1278SetRFFrequency(void)
{
	sx1278WriteByte( REG_LR_FRFMSB, Frequency[0]);  //写0x06寄存器
	sx1278WriteByte( REG_LR_FRFMID, Frequency[1]);  //写0x07寄存器
	sx1278WriteByte( REG_LR_FRFLSB, Frequency[2]);  //写0x08寄存器
}

/**
 * 功能：设置SX1278射频功率
 * 参数：
 *        power：功率值数组索引
 * 返回值：None
 */	
static void sx1278SetRFPower(unsigned char power )
{
	sx1278WriteByte( REG_LR_PADAC, 0x87);                   //设置更高功率
	sx1278WriteByte( REG_LR_PACONFIG,  power_data[power] ); //若没有这一句，频谱仪几乎测不到信号,但是可以进行正常收发。
}

/**
 * 功能：SX1278数据包配置
 * 参数：
 *        value：待设置值
 * 返回值：None
 */		
static void sx1278SetNbTrigPeaks(unsigned char value )
{
	unsigned char RECVER_DAT;
	RECVER_DAT = sx1278ReadByte( 0x31);  //Read RegDetectOptimize,
	RECVER_DAT = ( RECVER_DAT & 0xF8 ) | value; //process;
	sx1278WriteByte( 0x31, RECVER_DAT );  //write back;
}
/**
 * 功能：设置SX1278扩频因子
 * 参数：
 *        factor：扩频因子 7-12
 * 返回值：None
 */	
static void sx1278SetSpreadingFactor(unsigned char factor )
{
	unsigned char RECVER_DAT;
	sx1278SetNbTrigPeaks(3); //0x03-->SF7 to SF12
	RECVER_DAT=sx1278ReadByte( REG_LR_MODEMCONFIG2); //读0x1E寄存器  
	RECVER_DAT = ( RECVER_DAT & RFLR_MODEMCONFIG2_SF_MASK ) | ( factor << 4 );
	sx1278WriteByte( REG_LR_MODEMCONFIG2, RECVER_DAT ); 
}
	
/**
 * 功能：设置SX1278纠错编码
 * 参数：
 *        value：纠错编码率 1-4
 * 返回值：None
 */
static void sx1278SetErrCode(unsigned char value)
{	
	unsigned char RECVER_DAT;
	RECVER_DAT=sx1278ReadByte( REG_LR_MODEMCONFIG1); //读0x1D寄存器
	RECVER_DAT = ( RECVER_DAT & RFLR_MODEMCONFIG1_CODINGRATE_MASK ) | ( value << 1 );       //纠错编码率，位3~1。
	sx1278WriteByte( REG_LR_MODEMCONFIG1, RECVER_DAT);
}

/**
 * 功能：设置是否开启SX1278的CRC校验
 * 参数：
 *        enable：是否使能 0或1
 * 返回值：None
 */	
static void sx1278SetPacketCRC(BOOL_t enable )
{	
	unsigned char RECVER_DAT;
	RECVER_DAT= sx1278ReadByte( REG_LR_MODEMCONFIG2);  //读0x1E寄存器 
	RECVER_DAT = ( RECVER_DAT & RFLR_MODEMCONFIG2_RXPAYLOADCRC_MASK ) | ( enable << 2 );
	sx1278WriteByte( REG_LR_MODEMCONFIG2, RECVER_DAT );
}

/**
 * 功能：设置SX1278扩频带宽
 * 参数：
 *        bw：带宽值 6-9
 * 返回值：None
 */	
static void sx1278SetBandWidth(unsigned char bw)
{
	unsigned char RECVER_DAT;
	RECVER_DAT=sx1278ReadByte( REG_LR_MODEMCONFIG1);  //读0x1D寄存器
	RECVER_DAT = ( RECVER_DAT & RFLR_MODEMCONFIG1_BW_MASK ) | ( bw << 4 );
	sx1278WriteByte( REG_LR_MODEMCONFIG1, RECVER_DAT );
}

/**
 * 功能：设置是否将SX1278的报头设置为隐式模式
 * 参数：
 *        enable：使能状态,0或1
 * 返回值：None
 */		
static void sx1278SetImplicitHeader(BOOL_t enable)
{
	unsigned char RECVER_DAT;
	RECVER_DAT=sx1278ReadByte( REG_LR_MODEMCONFIG1 );  //读0x1D寄存器
	RECVER_DAT = ( RECVER_DAT & RFLR_MODEMCONFIG1_IMPLICITHEADER_MASK ) | ( enable );
	sx1278WriteByte( REG_LR_MODEMCONFIG1, RECVER_DAT );
}

/**
 * 功能：设置SX1278接收超时时间
 * 参数：
 *        value：超时值
 * 返回值：None
 */		
static void sx1278SetSymbTimeout(unsigned int value )
{
	unsigned char RECVER_DAT[2];
	RECVER_DAT[0]=sx1278ReadByte( REG_LR_MODEMCONFIG2 );    //读0x1E寄存器
	RECVER_DAT[1]=sx1278ReadByte( REG_LR_SYMBTIMEOUTLSB );  //读0x1F寄存器
	RECVER_DAT[0] = ( RECVER_DAT[0] & RFLR_MODEMCONFIG2_SYMBTIMEOUTMSB_MASK ) | ( ( value >> 8 ) & ~RFLR_MODEMCONFIG2_SYMBTIMEOUTMSB_MASK );
	RECVER_DAT[1] = value & 0xFF;
	sx1278WriteByte( REG_LR_MODEMCONFIG2, RECVER_DAT[0]);
	sx1278WriteByte( REG_LR_SYMBTIMEOUTLSB, RECVER_DAT[1]);
}

/**
 * 功能：设置SX1278负载字节长度
 * 参数：
 *        value：负载字节长度，最大值256,调用时要注意
 * 返回值：None
 */		
static void sx1278SetPayLoadLength(unsigned char value)
{
	sx1278WriteByte( REG_LR_PAYLOADLENGTH, value );  //写0x22寄存器，RegPayloadLength
} 
	
/**
 * 功能：是否使能SX1278低速率优化
 * 参数：
 *        enable:使能状态 0或1
 * 返回值：None
 */	
static void sx1278SetMobileNode(BOOL_t enable )
{	 
	unsigned char RECVER_DAT;
	RECVER_DAT=sx1278ReadByte( REG_LR_MODEMCONFIG3 );  //读0x26寄存器，低数据率优化
	RECVER_DAT = ( RECVER_DAT & RFLR_MODEMCONFIG3_MOBILE_NODE_MASK ) | ( enable << 3 );
	sx1278WriteByte( REG_LR_MODEMCONFIG3, RECVER_DAT );
}

/**
 * 功能：设置SX1278为连续接收接收模式
 * 参数：None
 * 返回值：None
 */
static void sx1278SetReceive (void)
{
	sx1278SetOpMode(Stdby_mode );
	sx1278WriteByte(REG_LR_IRQFLAGSMASK,IRQN_RXD_Value);  //0x11,打开接收中断
	sx1278WriteByte(REG_LR_HOPPERIOD,PACKET_MIAX_Value);  //0x24寄存器，设置频率跳变周期为最大
	sx1278WriteByte( REG_LR_DIOMAPPING1,0X00);            //DIO引脚映射设置，按默认
	sx1278WriteByte( REG_LR_DIOMAPPING2,0X00);	
	sx1278SetOpMode(Receiver_mode);                   //设置为连续接收模式
}

// LoRa_SCK	 PB3   LoRa_MISO  PB4    LoRa_MOSI    PB5
// LoRa_RST  PC10  LoRa_CS    PC12   LoRa_IRQ     PG6
void SX1278_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	NVIC_InitTypeDef NVIC_InitStruct;
	EXTI_InitTypeDef EXTI_InitStruct;
	SPI_InitTypeDef SPI_InitStruct;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 | RCC_APB2Periph_SYSCFG, ENABLE);	// 使能SPI1的时钟	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOG, ENABLE);	
	
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_SPI1); 
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource4, GPIO_AF_SPI1);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_SPI1);
	
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_Init(GPIOB, &GPIO_InitStruct);

	 /***********************SPI 工作模式****************************/
	SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置两线全双工
	SPI_InitStruct.SPI_Mode = SPI_Mode_Master;                       //设置为SPI主机
	SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;                   //8位数据帧格式
	SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;                          //时钟线空闲低电平
	SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;                        //第一个时钟沿(上升沿)采样，和SX1278一致
	SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;                           //软件控制NSS选通
	SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;//没有速度要求尽量设置的慢一点，这样可以兼容更多设备
	SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;                  //高位在前传输，和SX1278一致
	SPI_InitStruct.SPI_CRCPolynomial = 7;                            //设置默认值即可
	SPI_Init(SPI1, &SPI_InitStruct);                                 //配置生效

	SPI_Cmd(SPI1, ENABLE);                                           //开启SPI

	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_12;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_Init(GPIOC, &GPIO_InitStruct);
	GPIO_SetBits(GPIOC,GPIO_Pin_12 | GPIO_Pin_10);

	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6; 
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Init(GPIOG, &GPIO_InitStruct);
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOG, EXTI_PinSource6);
	
	// 配置IRQ引脚为外部中断
	EXTI_InitStruct.EXTI_Line = EXTI_Line6;
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStruct);

	NVIC_InitStruct.NVIC_IRQChannel = EXTI9_5_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
	NVIC_Init(&NVIC_InitStruct);

	// sx1278模块工作参数的配置
	sz1278Reset();                                          //复位设备
	sx1278SetOpMode(Sleep_mode);                            //设置睡眠模式
	sx1278SetLoRaFSK(LORA_mode);	                        // 设置扩频模式
	sx1278SetOpMode(Stdby_mode);                            // 设置为普通模式
	sx1278WriteByte( REG_LR_DIOMAPPING1,GPIO_VARE_1);           //写0x40寄存器,DIO引脚映射设置，设为00.
	sx1278WriteByte( REG_LR_DIOMAPPING2,GPIO_VARE_2);           //写0x41寄存器
	sx1278SetRFFrequency();                                 //频率设置
	sx1278SetRFPower(powerValue);                           //功率设置
	sx1278SetSpreadingFactor(SpreadingFactor);	            // 扩频因子设置
	sx1278SetErrCode(CodingRate);		                    //纠错编码率设置
	sx1278SetPacketCRC(true);			                    //CRC 校验打开
	sx1278SetBandWidth(Bw_Frequency);	                    //设置扩频带宽, 125khz
	sx1278SetImplicitHeader(false);		                    //同步头是显性模式
	sx1278SetPayLoadLength(0x40);                           //设置有效负载长度
	sx1278SetSymbTimeout(0x3FF);                            //设置接收超时时间，TimeOut = SymbTimeout * Ts。
	sx1278SetMobileNode(true); 	                            //低数据率优化，当有效数据速率较低时，必须使用LowDataRateOptimize位提高LoRa链路的鲁棒性。
	sx1278WriteByte(REG_LR_IRQFLAGS, 0xff); 
	sx1278WriteByte(REG_LR_FIFOTXBASEADDR, 0x00);
	sx1278WriteByte(REG_LR_FIFORXBASEADDR, 0x80);
	sx1278WriteByte(REG_LR_HOPPERIOD, 0x00);
	sx1278SetReceive();                                     //设置为连续接收模式
}

/**
 * 功能：发送数据包
 * 参数：
 *       buffer:数据包地址
 *       len:数据包长度
 * 返回值：None
 */		
void SX1278_TransmitPackets(unsigned char *buffer,unsigned char len)
{	
	unsigned char i;

	sg_sx1278TxBusy=1;
	sx1278SetOpMode( Stdby_mode );
	sx1278WriteByte( REG_LR_HOPPERIOD, 0 );	             //不做频率跳变
	sx1278WriteByte(REG_LR_IRQFLAGSMASK,IRQN_TXD_Value); //打开发送中断
	sx1278WriteByte( REG_LR_PAYLOADLENGTH, len);	     //最大数据包设置
	sx1278WriteByte( REG_LR_FIFOTXBASEADDR, 0);          //写Tx FIFO基址
	sx1278WriteByte( REG_LR_FIFOADDRPTR, 0 );            //FIFO指针
    
	sx1278SetNss(0);                                   //拉低NSS
	sx1278SendByte(0x80);			             //0X00 | 0X80，突发访问，写
	for(i = 0;i<len;i++)                             //将待发送数据发送到FIFO并等待发送
	{
		sx1278SendByte(*buffer);
		buffer++;
	}
	sx1278SetNss(1);                                       //拉高NSS
	sx1278WriteByte(REG_LR_DIOMAPPING1,0x40);            //设置0x40寄存器为0100 0000b，即设置发射完成指示映射到DIO0引脚
	sx1278WriteByte(REG_LR_DIOMAPPING2,0x00);
	sx1278SetOpMode(Transmitter_mode);               //设置为传输模式

  sx1278WriteByte(REG_LR_IRQFLAGS, 0xff);              //清零所有标志位，所有的DIOx口都会恢复低电平
}

void SX1278_ReceivePackets(unsigned char* buffer)
{
    unsigned char i;
    unsigned char len;

	sx1278SetReceive();
    
	if((sx1278ReadByte(REG_LR_IRQFLAGS)&0x40)==0x40)            //接收完成
	{
		if((sx1278ReadByte(REG_LR_MODEMCONFIG2)&0x04)==0x04)    //是否CRC校验完成
		{
			sx1278WriteByte (REG_LR_FIFOADDRPTR,0x00);          //设置SPI接口在FIFO缓冲区中的地址指针
			len = sx1278ReadByte(REG_LR_NBRXBYTES);             //读取最后一个包的字节数
			sx1278SetNss(0);
			sx1278SendByte(0x00);                        //0X00 | 0X00，突发访问，读。
            		
			for(i=0;i<len;++i)                              //读取接收到的数据到指定数组
			{
				buffer[i]= sx1278RcvByte();		
			}
			sx1278SetNss(1);
		}
		sx1278WriteByte(REG_LR_IRQFLAGS, 0xff);  
	}        
}

void SX1278_InterruptProcess(void)
{
	uint8_t i=0;
	uint8_t irqFlagReg=0;   //保存中断标志寄存器值
	irqFlagReg=sx1278ReadByte(REG_LR_IRQFLAGS);
	
	if((irqFlagReg&0x40)==0x40)
	{
		// 接收
		sx1278WriteByte(REG_LR_FIFOADDRPTR,0x00);
		sg_sx1278RecvLen=sx1278ReadByte(REG_LR_NBRXBYTES);
		sx1278SetNss(0);
		sx1278SendByte(0x00);
		
		for(i=0;i<sg_sx1278RecvLen;i++)
		{
			sg_sx1278RecvBuf[i]=sx1278RcvByte();
		}
		sx1278SetNss(1);
		sg_sx1278RecvFlag=1;
	}
	else if((irqFlagReg&0x08)==0x08)
	{
		// 发送
		sg_sx1278TxBusy=0;
		sx1278SetReceive();
	}
	
	sx1278WriteByte(REG_LR_IRQFLAGS, 0xff);
	sx1278SetReceive();
}


